----------------------------------------------------------------------------------
-- Company:        EECS 452
-- Engineer:       Kurt Metzger
-- 
-- Create Date:    13:21:40 04/05/2008 
-- Design Name: 
-- Module Name:    OV6220 - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity OV6220 is
    Port ( CamLines : in  STD_LOGIC_VECTOR (7 downto 0);
           CamHREF : in STD_LOGIC;
           CamPCLK : in STD_LOGIC;
           CamVSYN : in STD_LOGIC;
           CamPixelAddr : out  STD_LOGIC_VECTOR (17 downto 0);
           CamPixelPair : out  STD_LOGIC_VECTOR (15 downto 0);
           CamPixWrite : out  STD_LOGIC;
           CamPixAckIn : in  STD_LOGIC;
           clk : in  STD_LOGIC);
end OV6220;

architecture Behavioral of OV6220 is

   signal Pclkdelay : std_logic_vector(1 downto 0);
   signal PixelWrite : std_logic;
   signal HREF, PCLK, VSYN : std_logic;
   signal FrameStart : std_logic;
   signal data : std_logic_vector(7 downto 0);
   signal HREFold : std_logic;
   signal have_pixel_pair_flag : std_logic;
   signal flag : std_logic_vector(1 downto 0);
   signal pixel, pixela, pixelb : std_logic_vector(17 downto 0);
   signal pair : std_logic_vector(15 downto 0);
   signal Hstart, Vstart : std_logic;
   signal offset, line_start, origin : std_logic_vector(17 downto 0);

   type t_state is (s_idle, s_first, s_second);
   type t_pstate is (p_idle, p_next1, p_next2, p_next3);
   signal p_state : t_pstate := p_idle;
   signal pix_y : std_logic_vector (7 downto 0);
   signal y0, y1, cr, cb : std_logic_vector (9 downto 0);
   signal r0, g0, b0, r1, g1, b1, rv, gv, bv : std_logic_vector (9 downto 0);
   signal r0sel, r1sel, g0sel, g1sel, b0sel, b1sel : std_logic_vector (1 downto 0);
   signal test_counter : std_logic_vector(15 downto 0);
	signal COOL_COUNTER : std_logic_vector(15 downto 0);
	signal counter : std_logic_vector (15 downto 0);
	
begin

   data<= CamLines;
   HREF <= CamHREF;
   PCLK <= CamPCLK;
   VSYN <= CamVSYN;

   CamPixWrite <= PixelWrite;
   
   -- 8 bit test code needs 0x34 in register 0x12 .. gives YUYV order
   -- note: setting 8 bit mode using register 0x13 would give UYVY order
   
   CamClk : process(PCLK, HREF, VSYN)
   begin
      if rising_edge(PCLK) then
         HREFold <= HREF;
         case p_state is
            when p_idle =>
               if VSYN = '1' then
                  FrameStart <= '1';
						
						-- added slow cam code here:
--						if counter = X"001C" then
--							counter <= X"0000";
--						else
--							counter <= counter + '1';
--						end if;

               end if;
               if HREF = '1' then
                  if HREFold = '0' then
                     pixel(17) <= FrameStart;
                     pixel(16) <= '1';
                     FrameStart <= '0';
                  else
                     pixel(17) <= '0';
                     pixel(16) <= '0';
                  end if;
                  pixel(7 downto 0) <= data;   -- Y value
                  p_state <= p_next1;
               end if;
            when p_next1 =>
               pixel(15 downto 8) <= data;     -- U=Cb value
               have_pixel_pair_flag <= '0';
               p_state <= p_next2;
            when p_next2 =>
               pix_y <= data;                  -- Y value
               p_state <= p_next3;
            when p_next3 =>
               pixela <= pixel;
               pixelb <= "00" & data & pix_y;  -- V=Cr value
               have_pixel_pair_flag <= '1';
               p_state <= p_idle;
         end case;
      end if;
   end process;
                     
      
   Vstart <= pixela(17);
   Hstart <= pixela(16);   
   origin <= conv_std_logic_vector(288*320,origin'length);

   CamPixelAddr <= line_start+offset;
   
   -- remove offsets
   
   y0 <= ("00" & pixela(7 downto 0))  + "1111110000"; -- -16
   y1 <= ("00" & pixelb(7 downto 0))  + "1111110000"; -- -16
   cr <= ("00" & pixelb(15 downto 8)) + "1110000000"; -- V -128
   cb <= ("00" & pixela(15 downto 8)) + "1110000000"; -- U -128
   
   -- use nearest 1/16 to approximate Xilinx ap note XAPP931 adjustment values
   
	-- rv = 1 + 7/16 V
	
   rv <= cr + (cr(9) & cr(9) & cr(9 downto 2)) + (cr(9) & cr(9) & cr(9) & cr(9 downto 3))
	 + (cr(9) & cr(9) & cr(9) & cr(9) & cr(9 downto 4));

	-- gv = 12/16 V(cr) + 5/16 U(cb)

   gv <= (cr(9) & cr(9 downto 1)) + (cr(9) & cr(9) & cr(9 downto 2)) 
         + (cb(9) & cb(9) & cb(9 downto 2))
         + (cb(9) & cb(9) & cb(9) & cb(9) & cb(9 downto 4)); 

	-- bv = 1 + 12/16

    bv <= cb + (cb(9) & cb(9 downto 1)) + (cb(9) & cb(9) & cb(9 downto 2));
   
   -- using the two y values generate the color pixel values 
	
   r0 <= y0 + rv;
	r1 <= y1 + rv;
   b0 <= y0 + bv;
	b1 <= y1 + bv;
	g0 <= y0 - gv;
	g1 <= y1 - gv;
    
   -- this part packs two pixels into 16 bits 
   -- 8 msb is older pixel 8 lsb is newer pixel
   -- also handles overflows and underflows
   -- I've added gain of 2 to the values going to the D/A
   
   r0sel <= r0(9) & r0(8);
   pair(15 downto 13) <= "111" when r0sel = "01" else
                         "000" when r0sel = "10" else
                         "000" when r0sel = "11" else
                       --r0(6) & r0(5) & r0(4) when r0(7) = '0' else
                       --"111";
                         r0(7) & r0(6) & r0(5);
   
   g0sel <= g0(9) & g0(8);
   pair(12 downto 10) <= "111" when g0sel = "01" else
                         "000" when g0sel = "10" else
                         "000" when g0sel = "11" else
                       --g0(6) & g0(5) & g0(4) when g0(7) = '0' else
                       --"111";
                         g0(7) & g0(6) & g0(5);
                         
   b0sel <= b0(9) & b0(8);
   pair(9 downto 8) <= "11" when b0sel = "01" else
                       "00" when b0sel = "10" else
                       "00" when b0sel = "11" else
                     --b0(6) & b0(5) when b0(7) = '0' else
                     --"11";
                       b0(7) & b0(6);
                       
   r1sel <= r1(9) & r1(8);
   pair(7 downto 5) <= "111" when r1sel = "01" else
                       "000" when r1sel = "10" else
                       "000" when r1sel = "11" else
                       --r1(6) & r1(5) & r1(4) when r1(7) = '0' else
                       --"111";
                       r1(7) & r1(6) & r1(5);
   
   g1sel <= g1(9) & g1(8);
   pair(4 downto 2) <= "111" when g1sel = "01" else
                       "000" when g1sel = "10" else
                       "000" when g1sel = "11" else
                        --g1(6) & g1(5) & g1(4) when g1(7) = '0' else
                        --"111";
                       g1(7) & g1(6) & g1(5);
                       
   b1sel <= b1(9) & b1(8);
   pair(1 downto 0) <= "11" when b1sel = "01" else
                       "00" when b1sel = "10" else
                       "00" when b1sel = "11" else
                       --b1(6) & b1(5) when b1(7) = '0' else
                       --"11";
                     b1(7) & b1(6);

   -- overflow/underflow protected packed pixel generation done
	
   -- EECS 452 B1 adapter mounts the camera upside down.  This
	-- is corrected changing the byte ordering and moving backwards
	-- and upwards in display memory.
      
   CamOut : process(clk, have_pixel_pair_flag)
   begin
	
	-- added slow cam counter if here:
   --if counter = X"001C" then

      if rising_edge(clk) then
         flag <= flag(0) & have_pixel_pair_flag;
         if CamPixAckIn = '1' then PixelWrite <= '0'; end if;
         if Vstart = '1' then
            line_start <= origin;
            --offset <= (others=>'0');
            offset <= conv_std_logic_vector(175,offset'length);
         end if;
         
         if flag = "01" then
            --CamPixelPair <= pixelb(7 downto 0) & pixela(7 downto 0);
            --CamPixelPair <= pair; -- msbyte is older pixel lsbyte is newer pixel
            CamPixelPair <= pair(7 downto 0) & pair(15 downto 8); -- switch ordering
            
				--CamPixelPair <= X"0004";
				--CamPixelPair <= COOL_COUNTER;				
				--COOL_COUNTER <= COOL_COUNTER + '1';
				
				PixelWrite <= '1';
            if Hstart = '1' then 
               --offset <= (others=>'0');
               offset <= conv_std_logic_vector(175,offset'length);
               line_start <= line_start-320;
            else
               offset <= offset-1;
            end if;
               
         end if;
      end if;
	--end if;
   
	end process;   
   
end Behavioral;

